#include <kernel.h>
#include <libk/stdio.h>
#include <libk/string.h>
#include <libk/x86.h>

unsigned char *vidmem;

static unsigned crtc_reg, cons_width, cons_height, attrib, csr_x, csr_y = 0;

void update_cursor()
{
	unsigned short position=(csr_y*cons_width) + csr_x;
 
	outb(crtc_reg, 0x0F);
	outb(crtc_reg + 1, (unsigned char)(position&0xFF));

	outb(crtc_reg, 0x0E);
	outb(crtc_reg + 1, (unsigned char )((position>>8)&0xFF));
}

void cls()
{
	unsigned short i;
	unsigned char temp = 0x20;
	for (i=0; i<cons_width*cons_height*2; i++)
	{
		vidmem[i] = temp;
		vidmem[++i] = attrib;
	}
	update_cursor();
}

void scroll()
{
	if (csr_y >= cons_height)
	{
		csr_y--;
		unsigned int i;
		for (i=1; i<cons_height; i++)
		{
			memcpy((void *) (((unsigned long) vidmem) + ((i-1) * cons_width * 2)), (void *) (((unsigned long) vidmem) + (i * cons_width * 2)), cons_width * 2);
		}
		i--;
		memsetw((void *) (((unsigned long) vidmem) + (i * cons_width * 2)), (attrib << 8 | ' '), cons_width);
	}
}

void blink()
{
	unsigned char temp;
	outb(crtc_reg, 0x0A);
	temp = inb(crtc_reg + 1);
	temp ^= 0x20;
	outb(crtc_reg + 1, temp);
}

void putchar(unsigned char c)
{
	switch (c)
	{
		case '\b':
			if (csr_x != 0)
			{
				csr_x--;
			}
			break;
		case '\n':
			csr_y++;
		case '\r':
			csr_x=0;
			break;
		case '\t':
			do
			{
				csr_x++;
			} while (csr_x % 8 != 0);
			break;
		default:
			vidmem[(csr_y * cons_width + csr_x) * 2] = c;
			vidmem[(csr_y * cons_width + csr_x) * 2 + 1] = attrib;
			csr_x++;
			if (csr_x > cons_width)
			{
				csr_x = 0;
				csr_y++;
			}
	}
	scroll();
	update_cursor();
	return;
}

void init_text()
{
	if((inb(0x3CC) & 0x01) == 0)
	{
		crtc_reg = 0x3B4;
		vidmem = (unsigned char *) 0xC00B0000;
	}
	else
	{
		crtc_reg = 0x3D4;
		vidmem = (unsigned char *) 0xC00B8000;
	}

	attrib = 0x0F;
	cons_width = 80;
	cons_height = 25;
	cls();
}
